package cate.game.pvp.championrace;

import cate.common.table.d.GDChampionRace;
import cate.common.util.GameResult;
import cate.common.util.TimeTool;
import cate.game.GameBody;
import cate.game.event.championrace.ChampionRaceTimerEvent;
import cate.game.framework.ModuleMan;
import cate.game.pvp.championrace.data.ChampionRaceBetRecord;
import cate.game.pvp.championrace.data.ChampionRaceMsg;
import cate.game.pvp.championrace.dto.ChampionRaceAllBetRecordsData;
import cate.game.pvp.championrace.dto.ChampionRaceRankListData;
import cate.game.pvp.championrace.dto.ChampionRaceRedPacketRecordData;
import cate.game.pvp.championrace.data.ChampionRaceSpec;
import cate.game.pvp.championrace.dto.ChampionRaceTimerEventData;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.pvp.championrace.msg.*;
import cate.game.role.pvp.championrace.vo.ChampionRaceBetVO;
import cate.game.util.IntervalCounter;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;

public class GameChampionRaceManager extends ModuleMan {
    private final GameChampionRaceMsgManager message = new GameChampionRaceMsgManager();
    private final GameChampionRaceDataManager data = new GameChampionRaceDataManager();
    private final GameChampionRaceRecvManager recv = new GameChampionRaceRecvManager();
    @Getter
    private final TimerEventHandler eventHandler = new TimerEventHandler(data, message);
    @Getter
    private final BusinessHandler bizHandler = new BusinessHandler(message);

    @Override
    public void initDependent() throws Exception {
        message.initDependent();
        data.initDependent();
        recv.initDependent();
        loadSpecEvents();
    }

    @Override
    public void shutdown() {
        data.shutdownSafe();
    }

    public void markDirty(String roleUid) {
        data.iamdirty(roleUid);
    }

    private void loadSpecEvents() {
        final ChampionRaceSpec gameSrvSpec = getSpec();
        try{
            ChampionRaceTimerEventData specEventData = game.rpcSend().requestResponseCross(ChampionRaceMsg.GET_TIMER_EVENT, gameSrvSpec, ChampionRaceTimerEventData.class);
            if (specEventData != null && specEventData.spec != null) {
                ChampionRaceSpec nowSpec = specEventData.spec;
                boolean updateToNew = gameSrvSpec.getSeason() != nowSpec.getSeason() || CollectionUtils.isEmpty(specEventData.events);
                if (updateToNew) {
                    data.updateToNew(specEventData.spec, specEventData.openTime, specEventData.closeTime, specEventData.attributes, true);
                } else {
                    recv.loadUnSolvedSpecEvents(specEventData.events);
                }
            }
        } catch (Exception e) {
            //允许出错
            log.error("出错拉，肯定是跨服没连上");
        }
    }

    @Override
    public void initIndependent(GameBody game) throws Exception {
        super.initIndependent(game);
        message.initIndependent(game);
        data.initIndependent(game);
        recv.initIndependent(game);
    }

    public int getSeason() {
        return data.getSeason();
    }

    public long getNextSeasonStartTime() {
        return getSeasonStartTime() + GDChampionRace.WHOLE_SEASON_TIME;
    }

    public long getSeasonStartTime() {
        return data.getOpenTime() == 0 ? TimeTool.getNextSundayZeroTime() : data.getOpenTime();
    }

    public ChampionRaceSpec getSpec() {
        return data.getSpec();
    }

    public final class TimerEventHandler implements ChampionRaceTimerEvent.Handler {
        private final GameChampionRaceDataManager data;
        private final GameChampionRaceMsgManager message;
        public TimerEventHandler(GameChampionRaceDataManager data, GameChampionRaceMsgManager message) {
            this.data = data;
            this.message = message;
        }
        @Override
        public void onOpenEvent(ChampionRaceTimerEvent.OpenEvent openEvent) {
            data.onOpenEvent(openEvent);
        }
        @Override
        public void onRankSettleEvent(ChampionRaceTimerEvent.RankSettleEvent rankSettleEvent) {
            data.onRankSettleEvent(rankSettleEvent, message);
        }
        @Override
        public void onInvitationEvent(ChampionRaceTimerEvent.InvitationEvent invitationEvent) {
            data.onInvitationEvent(invitationEvent, message);
        }
        @Override
        public void onTrialEvent(ChampionRaceTimerEvent.TrialEvent trialEvent) {
            data.onTrialEvent(trialEvent, message);
        }
        @Override
        public void onKoEvent(ChampionRaceTimerEvent.KoEvent koEvent) {
            data.onKoEvent(koEvent, message);
        }
        @Override
        public void onFinalEvent(ChampionRaceTimerEvent.FinalEvent finalEvent) {
            data.onFinalEvent(finalEvent, message);
        }
        @Override
        public void onRankSwitchEvent(ChampionRaceTimerEvent.RankSwitchEvent rankSwitchEvent) {
            data.onRankSwitchEvent(rankSwitchEvent, message);
        }
        @Override
        public void onShowEvent(ChampionRaceTimerEvent.ShowEvent showEvent) {
            data.onShowEvent(showEvent);
        }
        @Override
        public void onRestEvent(ChampionRaceTimerEvent.RestEvent restEvent) {
            data.onRestEvent(restEvent);
        }
    }

    public final class BusinessHandler {
        private final GameChampionRaceMsgManager message;
        public BusinessHandler(GameChampionRaceMsgManager message) {
            this.message = message;
        }

        public ChampionRaceRedPacketRecordData getRedPacket(RoleSnapshot snapshot, ChampionRaceSpec spec) {
            return message.getRedPacket(snapshot, spec);
        }

        public ChampionRaceRedPacketRecordData getRoleRedPacket(ChampionRaceSpec spec, String roleUid) {
            return message.getRoleRedPacket(spec, roleUid);
        }

        public ChampionRaceAllBetRecordsData getAllBets() {
            return message.getAllBets();
        }

        public GameResult admire(String roleUid, int index) {
            return message.admire(roleUid, index);
        }

        public ChampionRaceRankListData getRankList() {
            return message.getRankList();
        }

        public ChampionRaceBetRoundResp getBetRound(ChampionRaceBetRoundReq req) {
            return message.getBetRounds(req);
        }

        public ChampionRaceBetRoundReportResp getBetRoundReports(ChampionRaceBetRoundReportReq req) {
            return message.getBetRoundReports(req);
        }

        public ChampionRaceRoundResp getRounds(String roleUid, ChampionRaceRoundReq req) {
            return message.getRounds(roleUid, req);
        }

        public ChampionRaceRoundReportResp getRoundReports(String roleUid, ChampionRaceRoundReportReq req) {
            return message.getRoundReports(roleUid, req);
        }

        public ChampionRaceGroupRoundResp getGroupRound(ChampionRaceGroupRoundReq req) {
            return message.getGroupRound(req);
        }

        public ChampionRaceGroupRoundReportResp getGroupRoundReports(ChampionRaceGroupRoundReportReq req) {
            return message.getGroupRoundReports(req);
        }

        public ChampionRaceGetPsResp getPs(ChampionRaceGetPsReq req) {
            return message.getPs(req);
        }

        public ChampionRaceBetRecord handleBetReq(ChampionRaceSpec spec, ChampionRaceBetReq req) {
            return message.handleBetReq(spec, req);
        }

        public ChampionRaceBetRecord getBetRecord(ChampionRaceSpec spec) {
            return message.getBetRecord(spec);
        }

        public GameResult<Void> doBet(Role role, ChampionRaceBetReq req) {
            GameResult<Void> r = new GameResult<>();
            ChampionRaceSpec querySpec = ChampionRaceSpec.ofNullStep(GameChampionRaceManager.this.getSpec());
            ChampionRaceBetRecord br = handleBetReq(GameChampionRaceManager.this.getSpec(), req);
            if (br == null) {
                return r.fail("您没有足够的竞猜币，请领取竞猜红包获取");
            }
            role.getPvp().championRace.afterBet(ChampionRaceBetVO.ofPre(br, GDChampionRace.FIXED_BET_NUM, req.side));
            game.role.activeForOnline(ar -> ar.getPvp().championRace.noticeBetData(querySpec, br));
            return r;
        }

        public boolean hasRecvdRedPacket(String roleUid) {
            return message.hasRecvdRedPacket(getSpec(), roleUid);
        }
    }

    private final IntervalCounter saveTrigger = new IntervalCounter(3600);
    public void tick() {
        recv.tick();
        if (saveTrigger.trigger()) {
            data.shutdownSafe();
        }
    }
}
